﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Framework.Common.Cache
{
    /// <summary>
    /// 自动创建key的缓存(如果使用对象做缓存的key,请override ToString())
    /// </summary>
    public static class SimpleCache
    {
        #region member

        private const string JoinParam = "_";
        private static readonly ICache Cache;

        #endregion

        #region static constructor

        static SimpleCache()
        {
            Cache = CacheFactory.CacheInstance;
        }

        #endregion

        #region create key

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="param1"></param>
        /// <returns></returns>
        private static string GetCacheKey<T>(Func<T> func)
        {
            var sb = new StringBuilder();
            sb.Append(func.Method.DeclaringType.FullName);
            sb.Append(JoinParam);
            sb.Append(func.Method.Name);
            return sb.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        private static string GetCacheKey<In1, T>(In1 param1, Func<In1, T> func)
        {
            var sb = new StringBuilder();
            sb.Append(func.Method.DeclaringType.FullName);
            sb.Append(JoinParam);
            sb.Append(func.Method.Name);
            sb.Append(JoinParam);
            if (param1 != null)
            {
                sb.Append(param1.ToString());
            }
            return sb.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="param1"></param>
        /// <returns></returns>
        private static string GetCacheKey<In1, In2, T>(In1 param1, In2 param2, Func<In1, In2, T> func)
        {
            var sb = new StringBuilder();
            sb.Append(func.Method.DeclaringType.FullName);
            sb.Append(JoinParam);
            sb.Append(func.Method.Name);
            sb.Append(JoinParam);
            if (param1 != null)
            {
                sb.Append(param1.ToString());
            }
            sb.Append(JoinParam);
            if (param2 != null)
            {
                sb.Append(param2.ToString());
            }
            sb.Append(JoinParam);
            return sb.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="param1"></param>
        /// <returns></returns>
        private static string GetCacheKey<In1, In2, In3, T>(In1 param1, In2 param2, In3 param3,
                                                            Func<In1, In2, In3, T> func)
        {
            var sb = new StringBuilder();
            sb.Append(func.Method.DeclaringType.FullName);
            sb.Append(JoinParam);
            sb.Append(func.Method.Name);
            sb.Append(JoinParam);
            if (param1 != null)
            {
                sb.Append(param1.ToString());
            }
            sb.Append(JoinParam);
            if (param2 != null)
            {
                sb.Append(param2.ToString());
            }
            sb.Append(JoinParam);
            if (param3 != null)
            {
                sb.Append(param3.ToString());
            }
            sb.Append(JoinParam);
            return sb.ToString();
        }

        #endregion

        #region Get

        /// <summary>
        /// 无参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T Get<T>(Func<T> func, DateTime? expiredTime = null)
        {
            string key = GetCacheKey(func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                return (T)result;
            }
            else
            {
                T t = func();
                if (t != null)
                {
                    if (expiredTime.HasValue)
                    {
                        Cache.Add(key, t, expiredTime.Value);
                    }
                    else
                    {
                        Cache.Add(key, t);
                    }
                    return t;
                }
            }
            return default(T);
        }

        /// <summary>
        /// 一个参数
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T Get<In1, T>(In1 param1, Func<In1, T> func, DateTime? expiredTime = null)
        {
            string key = GetCacheKey(param1, func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                return (T)result;
            }

            T t = func(param1);
            if (t != null)
            {
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, t, expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, t);
                }
                return t;
            }
            return default(T);
        }

        public static T Get<In1, In2, T>(In1 param1, In2 param2, Func<In1, In2, T> func, DateTime? expiredTime = null)
        {
            string key = GetCacheKey(param1, param2, func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                return (T)result;
            }

            T t = func(param1, param2);
            if (t != null)
            {
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, t, expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, t);
                }
                return t;
            }
            return default(T);
        }

        public static T Get<In1, In2, In3, T>(In1 param1, In2 param2, In3 param3, Func<In1, In2, In3, T> func,
                                              DateTime? expiredTime = null)
        {
            string key = GetCacheKey(param1, param2, param3, func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                return (T)result;
            }

            T t = func(param1, param2, param3);
            if (t != null)
            {
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, t, expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, t);
                }
                return t;
            }
            return default(T);
        }

        /// <summary>
        /// 根据一组TKey得到T
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IList<T> GetListFromCache<TKey, T>(IList<TKey> source, Func<TKey, T> func) where T : new()
        {
            var result = new List<T>();
            foreach (TKey t in source)
            {
                T singleFromCache = Get(t, func);
                if (singleFromCache != null)
                    result.Add(singleFromCache);
            }
            return result;
        }

        #endregion

        #region update

        /// <summary>
        /// 无参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public static void Update<T>(Func<T> func, Func<T, T> updateMethod, DateTime? expiredTime = null)
        {
            string key = GetCacheKey(func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, updateMethod((T)result), expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, updateMethod((T)result));
                }
            }
        }

        /// <summary>
        /// 一个参数
        /// </summary>
        /// <typeparam name="TIn1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <param name="updateMethod"> </param>
        /// <param name="expiredTime"> </param>
        /// <returns></returns>
        public static void Update<TIn1, T>(TIn1 param1, Func<TIn1, T> func, Func<T, T> updateMethod,
                                          DateTime? expiredTime = null)
        {
            string key = GetCacheKey(param1, func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, updateMethod((T)result), expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, updateMethod((T)result));
                }
            }
        }

        /// <summary>
        /// 两个参数
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <param name="updateMethod"></param>
        public static void Update<In1, In2, T>(In1 param1, In2 param2, Func<In1, In2, T> func, Func<T, T> updateMethod,
                                               DateTime? expiredTime = null)
        {
            string key = GetCacheKey(param1, param2, func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, updateMethod((T)result), expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, updateMethod((T)result));
                }
            }
        }

        /// <summary>
        /// 三个参数
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <param name="updateMethod"></param>
        public static void Update<In1, In2, In3, T>(In1 param1, In2 param2, In3 param3, Func<In1, In2, In3, T> func,
                                                    Func<T, T> updateMethod, DateTime? expiredTime = null)
        {
            string key = GetCacheKey(param1, param2, param3, func);
            object result = Cache.GetData(key);
            if (result != null)
            {
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, updateMethod((T)result), expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, updateMethod((T)result));
                }
            }
        }

        #endregion

        #region reset

        /// <summary>
        /// 无参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public static void Reset<T>(Func<T> func, DateTime? expiredTime = null)
        {
            T t = func();
            if (t != null)
            {
                string key = GetCacheKey(func);
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, t, expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, t);
                }
            }
        }

        /// <summary>
        /// 一个参数
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static void Reset<In1, T>(In1 param1, Func<In1, T> func, DateTime? expiredTime = null)
        {
            T t = func(param1);
            if (t != null)
            {
                string key = GetCacheKey(param1, func);
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, t, expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, t);
                }
            }
        }

        /// <summary>
        /// 2个参数
        /// </summary>
        /// <typeparam name="TIn1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TIn2"> </typeparam>
        /// <param name="param1"></param>
        /// <param name="param2"> </param>
        /// <param name="func"></param>
        /// <param name="expiredTime"> </param>
        /// <returns></returns>
        public static void Reset<TIn1, TIn2, T>(TIn1 param1, TIn2 param2, Func<TIn1, TIn2, T> func,
                                              DateTime? expiredTime = null)
        {
            T t = func(param1, param2);
            if (t != null)
            {
                string key = GetCacheKey(param1, param2, func);
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, t, expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, t);
                }
            }
        }

        /// <summary>
        /// 3个参数
        /// </summary>
        /// <typeparam name="In1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static void Reset<In1, In2, In3, T>(In1 param1, In2 param2, In3 param3, Func<In1, In2, In3, T> func,
                                                   DateTime? expiredTime = null)
        {
            T t = func(param1, param2, param3);
            if (t != null)
            {
                string key = GetCacheKey(param1, param2, param3, func);
                if (expiredTime.HasValue)
                {
                    Cache.Add(key, t, expiredTime.Value);
                }
                else
                {
                    Cache.Add(key, t);
                }
            }
        }

        #endregion

        #region remove

        /// <summary>
        /// 无参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public static void Remove<T>(Func<T> func)
        {
            string key = GetCacheKey(func);
            Cache.Remove(key);
        }

        /// <summary>
        /// 一个参数
        /// </summary>
        /// <typeparam name="TIn1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="param1"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static void Remove<TIn1, T>(TIn1 param1, Func<TIn1, T> func)
        {
            var key = GetCacheKey(param1, func);
            Cache.Remove(key);
        }

        /// <summary>
        /// 2个参数
        /// </summary>
        /// <typeparam name="TIn1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TIn2"> </typeparam>
        /// <param name="param1"></param>
        /// <param name="param2"> </param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static void Remove<TIn1, TIn2, T>(TIn1 param1, TIn2 param2, Func<TIn1, TIn2, T> func)
        {
            string key = GetCacheKey(param1, param2, func);
            Cache.Remove(key);
        }

        /// <summary>
        /// 3个参数
        /// </summary>
        /// <typeparam name="TIn1"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TIn2"> </typeparam>
        /// <typeparam name="TIn3"> </typeparam>
        /// <param name="param1"></param>
        /// <param name="param3"> </param>
        /// <param name="func"></param>
        /// <param name="param2"> </param>
        /// <returns></returns>
        public static void Remove<TIn1, TIn2, TIn3, T>(TIn1 param1, TIn2 param2, TIn3 param3, Func<TIn1, TIn2, TIn3, T> func)
        {
            string key = GetCacheKey(param1, param2, param3, func);
            Cache.Remove(key);
        }

        #endregion
    }
}